package com.gjw.designpattern.singleton;

/**
 * 单例模式
 * 私有对象 私有的无参构造，公有的获取方法
 * @Author gjw
 */
public class Singleton {

//--------------------懒汉方式------------------
//类加载时不生成对象，第一次调用的时候才创建对象
// 单线程模式   多线程模式下会出现问题
//--------------------懒汉方式------------------
//    private static Singleton singleton = null;
//    private Singleton(){ }
//
//    public Singleton getSingleton(){
//
//        if(singleton == null){
//            singleton = new Singleton();
//        }
//        return singleton;
//    }


//--------------------懒汉方式------------------
//类加载时不生成对象，第一次调用的时候才创建对象
//线程安全的懒汉式：
//使用synchronized关键字：
//  1.将并行改为串行执行，保证实例化只有一次
//  2.实例化成功后，依旧有锁，那么在并发访问时，等同于读读加锁，性能较差不推荐
//--------------------懒汉方式------------------
//    private static Singleton singleton = null;
//    private Singleton(){};
//    public static synchronized Singleton getSingleton(){
//        if(singleton == null){
//            singleton = new Singleton();
//        }
//        return singleton;
//    }

//--------------------懒汉方式------------------
//类加载时不生成对象，第一次调用的时候才创建对象
//线程安全的懒汉式：双检锁 + volatile
//  1.多线程时，可能会有多个线程同时执行步骤2，所以可以考虑在步骤2加锁限制，如下
//  2.步骤2加锁后，仍旧有问题：
//      1.当多个线程同时执行到 synchronized时，程序由并行转为串行执行，此时已经解决了创建多个对象的问题
//      2.当线程A执行到步骤2，线程B执行到步骤1的时候，可能会由于JVM指令重排的原因，造成步骤3中返回不完整的实例对象
//      3.对上一步的解释：
//          ·指令重排序：是编译器在不改变执行效果的前提下，对指令顺序进行调整，从而提高执行效率的过程
//          ·new对象包含的过程：步骤2中  hungrySingleton = new LazySingletonSafe2();
//              1.分配内存
// *            2.引用指向内存        hungrySingleton
// *            3.内存中存放实例      new LazySingletonSafe2()
// *        ·由上可知2,3依赖于1，所以指令重排时，2,3可能会交换，交换后会出现问题：
//          当A线程执行到步骤2的时候，指令重排序，导致引用指向了空内存（此时1,3执行，2未执行）
//          同时B线程到达步骤1，发现其引用指向不为null，就会返回一个不完整的实例对象
//          ·解决方法：
//              对私有静态属性 添加volatile关键字，保证内存可见性和防止指令重排
//      4.综上：懒汉式线程不安全的两个问题主要来源于：
//          1.创建多个对象    synchronized
//          2.指令重排        volatile
//--------------------懒汉方式------------------
    private static volatile Singleton singleton = null;
    private Singleton(){}
    public static Singleton getInstance(){
        if(singleton == null){
            synchronized (Singleton.class){
                if(singleton == null){
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }



//--------------------饿汉方式------------------
// 类加载时对象
// 多线程模式下也是线程安全的
//--------------------饿汉方式------------------
//    private static final Singleton singleton = new Singleton();
//    private Singleton(){ }
//
//    public static Singleton getSingleton(){
//        return singleton;
//    }

}
